package com.hullbreach.rogue;

import java.util.HashMap;

import org.andengine.engine.camera.ZoomCamera;
import org.andengine.engine.camera.hud.HUD;
import org.andengine.engine.handler.IUpdateHandler;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.primitive.Rectangle;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.text.Text;
import org.andengine.entity.text.TextOptions;
import org.andengine.entity.util.FPSLogger;
import org.andengine.extension.tmx.TMXLayer;
import org.andengine.extension.tmx.TMXLoader;
import org.andengine.extension.tmx.TMXProperties;
import org.andengine.extension.tmx.TMXTile;
import org.andengine.extension.tmx.TMXTileProperty;
import org.andengine.extension.tmx.TMXTiledMap;
import org.andengine.extension.tmx.TMXLoader.ITMXTilePropertiesListener;
import org.andengine.extension.tmx.util.exception.TMXLoadException;
import org.andengine.input.touch.TouchEvent;
import org.andengine.input.touch.controller.MultiTouch;
import org.andengine.input.touch.detector.PinchZoomDetector;
import org.andengine.input.touch.detector.PinchZoomDetector.IPinchZoomDetectorListener;
import org.andengine.input.touch.detector.ScrollDetector;
import org.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
import org.andengine.input.touch.detector.SurfaceScrollDetector;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.font.FontFactory;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.atlas.bitmap.BuildableBitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.source.IBitmapTextureAtlasSource;
import org.andengine.opengl.texture.atlas.buildable.builder.BlackPawnTextureAtlasBuilder;
import org.andengine.opengl.texture.atlas.buildable.builder.ITextureAtlasBuilder.TextureAtlasBuilderException;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.TextureRegionFactory;
import org.andengine.opengl.texture.region.TiledTextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import org.andengine.util.Constants;
import org.andengine.util.HorizontalAlign;
import org.andengine.util.debug.Debug;
import android.graphics.Typeface;
import android.view.MotionEvent;
import android.widget.Toast;


public class GameActivity extends SimpleBaseGameActivity implements IOnSceneTouchListener, IScrollDetectorListener, IPinchZoomDetectorListener {
	// ===========================================================
	// Constants
	// ===========================================================

	private static final int CAMERA_WIDTH = 720;
	private static final int CAMERA_HEIGHT = 480;

	// ===========================================================
	// Fields
	// ===========================================================

	//Camera
	private ZoomCamera mZoomCamera;
	private BitmapTextureAtlas mCardDeckTexture;

	//Scenes
	private Scene mScene;

	//Zoom and Scroll
	private SurfaceScrollDetector mScrollDetector;
	private PinchZoomDetector mPinchZoomDetector;
	private float mPinchZoomStartedCameraZoomFactor;
	private boolean clicked = false;	
	private float mTouchX = 0, mTouchY = 0, mTouchOffsetX = 0, mTouchOffsetY = 0;
	
	//player
	private GameObject mPlayer;
	private BuildableBitmapTextureAtlas mBitmapTextureAtlas;	
	private TiledTextureRegion mPlayerTextureRegion;

	//test enemy
	private GameObject mEnemy;
	
	//Scheduler
	private Scheduler mSchedule;
	/* TESTING SCHEDULER */
	
	//Map
	private Map mMap;
	private TMXTiledMap mTMXTiledMap;
    private TMXLayer tmxLayer;
    private TMXTile tmxTile;
    private Rectangle currentTileRectangle;
    
	//Map generation
	ship generator;
	final static int TILE_SIZE = 16;
	int mapSizeX = 20;
	int mapSizeY = 20;
	int mapRoomObjects = 10;
    
	
	// ===========================================================
	// Constructors
	// ===========================================================

	// HUD Text and HUD
    private BitmapTextureAtlas mFontTexture;
    private Font mFont;
    HUD hud = new HUD();
    private float maxZoom;
	
	// ===========================================================
	// Getter & Setter
	// ===========================================================

	// ===========================================================
	// Methods for/from SuperClass/Interfaces
	// ===========================================================

	@Override
	public EngineOptions onCreateEngineOptions() {
		this.mZoomCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);

		final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mZoomCamera);

		//Check for multi touch (for pinch zoom)
		if(MultiTouch.isSupported(this)) {
			if(MultiTouch.isSupportedDistinct(this)) {
				Toast.makeText(this, "MultiTouch detected --> Both controls will work properly!", Toast.LENGTH_SHORT).show();
			} else {
				Toast.makeText(this, "MultiTouch detected, but your device has problems distinguishing between fingers.\n\nControls are placed at different vertical locations.", Toast.LENGTH_LONG).show();
			}
		} else {
			Toast.makeText(this, "Sorry your device does NOT support MultiTouch!\n\n(Falling back to SingleTouch.)\n\nControls are placed at different vertical locations.", Toast.LENGTH_LONG).show();
		}

		return engineOptions;
	}

	@Override
	public void onCreateResources() {
		BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
		
		// Load Sprites	
		this.mBitmapTextureAtlas = new BuildableBitmapTextureAtlas(this.getTextureManager(), 512, 256, TextureOptions.NEAREST);
		this.mPlayerTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "player_tiled.png", 2, 1);
		this.mBitmapTextureAtlas.load();
				
    	// HUD text
		this.mFont = FontFactory.create(this.getFontManager(), this.getTextureManager(), 256, 256, Typeface.create(Typeface.DEFAULT, Typeface.BOLD), 16);
		this.mFont.load();		
		
		// Load all required Resources
		try {
			this.mBitmapTextureAtlas.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(0, 0, 1));
			this.mBitmapTextureAtlas.load();
		} catch (TextureAtlasBuilderException e) {
			Debug.e(e);
		}
		
		
	}

	@Override
	public Scene onCreateScene() {
		this.mEngine.registerUpdateHandler(new FPSLogger());

		this.mScene = new Scene();
		this.mScene.setOnAreaTouchTraversalFrontToBack();

		//black background
		this.mScene.setBackground(new Background(0.00f, 0.00f, 0.00f));
		//blue background
		//this.mScene.setBackground(new Background(0.09804f, 0.6274f, 0.8784f));

		//initialise scroll and pinch detectors
		this.mScrollDetector = new SurfaceScrollDetector(this);
		this.mPinchZoomDetector = new PinchZoomDetector(this);
		
		//initialise scene touch detector
		this.mScene.setOnSceneTouchListener(this);
		this.mScene.setTouchAreaBindingOnActionDownEnabled(true);

		//initialise vertex buffer
		final VertexBufferObjectManager vertexBufferObjectManager = this.getVertexBufferObjectManager();
		
		//DEBUG DUNGEON
		//final Text leftText = new Text(10, 10, this.mFont, "THIS IS A TEST", new TextOptions(HorizontalAlign.LEFT), vertexBufferObjectManager);
		//this.mScene.attachChild(leftText);
			
		//LOAD TMX MAP
		try {
			final TMXLoader tmxLoader = new TMXLoader(this.getAssets(), this.mEngine.getTextureManager(), TextureOptions.BILINEAR_PREMULTIPLYALPHA, this.getVertexBufferObjectManager(), new ITMXTilePropertiesListener() {
				@Override
				public void onTMXTileWithPropertiesCreated(final TMXTiledMap pTMXTiledMap, final TMXLayer pTMXLayer, final TMXTile pTMXTile, final TMXProperties<TMXTileProperty> pTMXTileProperties) {

				}
			});
			this.mTMXTiledMap = tmxLoader.loadFromAsset("shipmap.tmx");

		} catch (final TMXLoadException e) {
			Debug.e(e);
		}

		//assign map object
		
		
		//attach map to scene
		final TMXLayer tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
		this.mScene.attachChild(tmxLayer);	
		
		
		
		//Generate Ship
		//generator = new ship();
		//generator.createShip(mapSizeX, mapSizeY, mapRoomObjects);		

		//Get starting point
		GameManager.getInstance().mStartTileLoc = findTile("breach",tmxLayer);
		
		//create new scheduler and add to game instance
		GameManager.getInstance().setScheduler( new Scheduler() );
		mSchedule = GameManager.getInstance().getScheduler();
		
		//create Map
		GameManager.getInstance().setMap( new Map() );
		mMap = GameManager.getInstance().getMap();
		//GameManager.getInstance().setCurrentTMXTiledMap( mTMXTiledMap );
		
		//Create Player on starting point
		this.mPlayer = GameManager.getInstance().getScheduler().addActor( new Player(GameManager.getInstance().mStartTileLoc[0]*16, GameManager.getInstance().mStartTileLoc[1]*16, mPlayerTextureRegion, vertexBufferObjectManager));
		
		/* Draw Player. */
		this.mPlayer.animate(2000);
		this.mScene.attachChild(mPlayer);		
			
        /* generate some enemies */
		mEnemy = GameManager.getInstance().getScheduler().addActor( new EnemySecurityGuard(16*20, 16*8, mPlayerTextureRegion, vertexBufferObjectManager) );
		this.mScene.attachChild(mEnemy);
		this.mEnemy.animate(2000);
					
		
		this.mScene.registerUpdateHandler(new IUpdateHandler() {
			@Override
			public void reset() { }

			@Override
			public void onUpdate(final float pSecondsElapsed) {
				GameManager.getInstance().getScheduler().tick();
			}
		});
		
		return this.mScene;
	}

	@Override
	public void onScrollStarted(final ScrollDetector pScollDetector, final int pPointerID, final float pDistanceX, final float pDistanceY) {
		final float zoomFactor = this.mZoomCamera.getZoomFactor();
		this.mZoomCamera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
		clicked = false;
	}

	@Override
	public void onScroll(final ScrollDetector pScollDetector, final int pPointerID, final float pDistanceX, final float pDistanceY) {
		final float zoomFactor = this.mZoomCamera.getZoomFactor();
		this.mZoomCamera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
		clicked = false;
	}
	
	@Override
	public void onScrollFinished(final ScrollDetector pScollDetector, final int pPointerID, final float pDistanceX, final float pDistanceY) {
		final float zoomFactor = this.mZoomCamera.getZoomFactor();
		this.mZoomCamera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
		clicked = false;
	}

	@Override
	public void onPinchZoomStarted(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent) {
		this.mPinchZoomStartedCameraZoomFactor = this.mZoomCamera.getZoomFactor();
		clicked = false;
	}

	@Override
	public void onPinchZoom(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent, final float pZoomFactor) {
		this.mZoomCamera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
		clicked = false;
	}

	@Override
	public void onPinchZoomFinished(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent, final float pZoomFactor) {
		this.mZoomCamera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
		clicked = false;
	}


	@Override
	public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
		this.mPinchZoomDetector.onTouchEvent(pSceneTouchEvent);
		    
		if(this.mPinchZoomDetector.isZooming()) {
			this.mScrollDetector.setEnabled(false);
			clicked = false;
		} else {
			if(pSceneTouchEvent.isActionDown()) {
				this.mScrollDetector.setEnabled(true);
				mTouchX = pSceneTouchEvent.getX();
				mTouchY = pSceneTouchEvent.getY();
				
				clicked = true;
			}
			if(pSceneTouchEvent.isActionUp()) {
				if (clicked == true)
				{
					if (GameManager.getInstance().getScheduler().playersTurn == true)
					{
						//can intecept GUI clicks here or trigger player action
						boolean guiClick = false;
						
						if (guiClick) //gui action
						{
							
						}
						else 
						{
							//player action
							
							//What action did user take?
							
							//Clicked a floor tile (is it empty or has it got an item or enemy?)
							
							//Clicked a wall (do nothing)
							
							
							
							targetTile(mTouchX, mTouchY);
							//Debug.e("CLICKED!");
							clicked = false;

							mPlayer.energy = mPlayer.act();
							//DO GAME LOOP HERE
							//Is Player Turn True? GameManager.getInstance().mPlayerTurn == true
							//{
							//If so do something
							//} else {
							//keep processing game loop, move enemies etc.
							//}
							GameManager.getInstance().getScheduler().playersTurn = false;
							GameManager.getInstance().getScheduler().unlock();							
						}
					}
				}
			}
			
			this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
		}

		return true;
	}

	// ===========================================================
	// Methods
	// ===========================================================

	private void targetTile(final float coordX, final float coordY)
	{		
		/* Now we are going to create a rectangle where the player clicked. */
        this.currentTileRectangle = new Rectangle(0, 0, this.mTMXTiledMap.getTileWidth(), this.mTMXTiledMap.getTileHeight(), this.getVertexBufferObjectManager());
		this.currentTileRectangle.setColor(1, 0, 0, 0.25f);
		this.mScene.attachChild(this.currentTileRectangle);
		
        TMXLayer tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
        tmxTile = tmxLayer.getTMXTileAt(coordX,coordY);
        if(tmxTile != null){
        	this.currentTileRectangle.setPosition(tmxTile.getTileX(), tmxTile.getTileY());
        	final Integer test = tmxTile.getGlobalTileID();
        	//Debug.e(test.toString());
        	
        	 final TMXProperties<TMXTileProperty> pTMXTileProperties;
             pTMXTileProperties = tmxTile.getTMXTileProperties(mTMXTiledMap);
             
             if(pTMXTileProperties != null)
             { //Avoid NullPointerException
            	 if(pTMXTileProperties.containsTMXProperty("name", "wall") || pTMXTileProperties.containsTMXProperty("name", "wall2"))
            	 {
            		 Debug.e("WALL");
            		 //tmxTile.setGlobalTileID(mTMXTiledMap, 1);
            	 }
            	 else
            	 { //Allow to move over non-property tiles.
                     Debug.e("Not a wall");
            	 }        	
        	
             }
		
        }    
           
	}
        
	/*
	private void checkTile()
	{
	
	if(pValueX == 1.0) {
        final float[] playerFootCordinates = player.convertLocalToSceneCoordinates(12, 31);
        TMXTile tmxTile = tmxLayer.getTMXTileAt(playerFootCordinates[Constants.VERTEX_INDEX_X]+16, playerFootCordinates[Constants.VERTEX_INDEX_Y]);
        final TMXProperties<TMXTileProperty> pTMXTileProperties;
        pTMXTileProperties = tmxTile.getTMXTileProperties(mTMXTiledMap);
       
        if(pTMXTileProperties != null){ //Avoid NullPointerException
                if(!pTMXTileProperties.containsTMXProperty("collide", "true"))
                {
                        player.setPosition(player.getX()+8, player.getY());
                        //physicsHandler.setVelocity(pValueX * 100, pValueY * 100);
                }
        }else { //Allow to move over non-property tiles.
                player.setPosition(player.getX()+8, player.getY());
        }
    } else if(pValueX == -1.0) { //Move Left
            final float[] playerFootCordinates = player.convertLocalToSceneCoordinates(12, 31);
            TMXTile tmxTile = tmxLayer.getTMXTileAt(playerFootCordinates[Constants.VERTEX_INDEX_X]-16, playerFootCordinates[Constants.VERTEX_INDEX_Y]);
            final TMXProperties<TMXTileProperty> pTMXTileProperties;
            pTMXTileProperties = tmxTile.getTMXTileProperties(mTMXTiledMap);
           
            if(pTMXTileProperties != null){
                    if(!pTMXTileProperties.containsTMXProperty("collide", "true"))
                    {
                            player.setPosition(player.getX()-8, player.getY());
                            //physicsHandler.setVelocity(pValueX * 100, pValueY * 100);
                    }
            }
            else {
                    player.setPosition(player.getX()-8, player.getY());
            }
    }		
	*/
	
	//Can delete this when maps are auto generated
    private int[] findTile( final String tileName, final TMXLayer tmxLayer )
    {
        //TMXLayer tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
        int tmxRows = tmxLayer.getTileRows();
        int tmxCols = tmxLayer.getTileColumns();
        int[] tileCoord = {0,0};
        
        for (int y=0;y<tmxRows;y++)
        {
            for (int x=0;x<tmxCols;x++)
            {
            	tmxTile = tmxLayer.getTMXTile(x, y);
                
                if(tmxTile != null){
                	//final Integer test = tmxTile.getGlobalTileID();
                	final TMXProperties<TMXTileProperty> pTMXTileProperties;
                    pTMXTileProperties = tmxTile.getTMXTileProperties(mTMXTiledMap);
					if(pTMXTileProperties != null)
					{
						 if(pTMXTileProperties.containsTMXProperty("name", tileName))
						 {
							 //Debug.e("FOUND IT");
							 tileCoord[0] = x;
							 tileCoord[1] = y;
							 
							 return tileCoord;
						 }        	
					 }
                }                	
            }
        	
        }
        
        return tileCoord;
    }
	
	
	
	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================
}
